/* Includes ------------------------------------------------------------------*/
#include "http.h"
#include <stdarg.h>
#include <string.h>
#include <stddef.h>
#include <stdio.h>
/* typedef -------------------------------------------------------------------*/
/* define --------------------------------------------------------------------*/
/* macro ---------------------------------------------------------------------*/
/* variables -----------------------------------------------------------------*/
/* function prototypes -------------------------------------------------------*/
/* functions -----------------------------------------------------------------*/
void rsvmemcpy(void *dst, void *src, size_t len)
{
	uint8_t *d = (uint8_t *)dst, *s = (uint8_t *)src;
	for(int i=0; i<len; i++)
	{
		*(d --) = *(s --);
	}
}

char *Http_Content(void *buffer);
char *Http_Tail(void *buffer, size_t size);

/*********************************************************************************************

  * @brief  Nat_ExecuteCommand
  * @param  buffer,	buffer which fill entire http packet
			size, 	buffer max size;
			method, like GET POST
			host, 	host
			port,	port
			url,	url
  * @return 0: successfully
  * @remark 

  ********************************************************************************************/
int Http_Create(void *buffer, size_t size, char *method, char *host, int port, char *url, ...)
{
	char *message = (char *)buffer;
	
	memset(buffer, 0, size);
	sprintf(message, "%s ", method);
	
	va_list args;
    va_start(args, url);
	vsprintf(message + strlen(message), url, args);
	va_end(args);
	
	sprintf(message + strlen(message), " HTTP/1.1\r\n"
									   "Host: %s:%d\r\n\r\n", 
										host, port);
	 
	return 0;
}
/*********************************************************************************************

  * @brief  Http_AddHeader
  * @param  buffer, buffer which fill entire http packet
			header, the header string which need insert into packet
  * @return 0: successfully
			-1, faild, cant get content pointer
  * @remark 

  ********************************************************************************************/
int _Http_AddHeader(void *buffer, size_t size, char *header)
{
	char *content = Http_Content(buffer);
	if(content == NULL)
	{	return -1;	}
	
	/* find last content char */
	char *tail = Http_Tail(buffer, size), *location;
	
	int sizeContent = 0;
	sizeContent = (uint32_t)tail - (uint32_t)content + 1;
	
	/* move content forward to make space for new header */
	location = tail + strlen(header) + 2;
	rsvmemcpy(location, tail, sizeContent);
	
	memcpy(content - 2, header, strlen(header));
	content = content - 2 + strlen(header);
	content[0] = '\r';
	content[1] = '\n';
	content[2] = '\r';
	content[3] = '\n';
	
	return 0;
}
int Http_AddHeader(void *buffer, size_t size, char *format, ...)
{
	char *header = (char *)malloc(512);
	if(header == NULL)
	{	return -1;	}
	memset(header, 0, 512);
	
	va_list args;
    va_start(args, format);
	vsprintf(header, format, args);
	va_end(args);
	
	int result = _Http_AddHeader(buffer, size, header);
	
	free(header);
	
	return result;
}
/*********************************************************************************************

  * @brief  Http_EditContent
  * @param  buffer, buffer which fill entire http packet
			size, max size to fill 
			formt, content string format and args
  * @return 0: successfully
			-1, faild, cant get content pointer
  * @remark 

  ********************************************************************************************/
int Http_EditContent(void *buffer, size_t size, char *format, ...)
{
	char *content = Http_Content(buffer);
	if(content == NULL)
	{	return -1;	}
	
	va_list args;
    va_start(args, format);
	vsnprintf(content, (size - ((uint32_t)(content) - (uint32_t)buffer)),  format, args);
	va_end(args);
	
	return 0;
}
/*********************************************************************************************

  * @brief  Http_AddContent
  * @param  buffer, buffer which fill entire http packet
			size, max length to fill into buffer
			data, content pointer
			dataSize, content length, if dataSize = 0, content length is use strlen(data)
  * @return 0: successfully
			-1, faild, cant get content pointer or remain size is not enough
  * @remark 

  ********************************************************************************************/	
int Http_AddContent(void *buffer, size_t size, void *data, size_t dataSize)
{
	int contentSize = ((dataSize == 0)? strlen((char*)data): dataSize);
	char *content = Http_Content(buffer);
	if(content == NULL)
	{	return -1;	}
	
	int sizeRemain = (size - ((uint32_t)(content) - (uint32_t)buffer));
	
	if(sizeRemain < contentSize)
	{	return -1;	}
	
	memset(content, 0, sizeRemain);
	memcpy(content, data, contentSize);
	
	return 0;
}
/*********************************************************************************************

  * @brief  Http_FillContentLength
  * @param  buffer, buffer which fill entire http packet
			size, max length to fill into buffer\
			specify, if set to 0, function will calculate content-length
					 when a big packt split several blocks, 
					 Content-length is the size of entire packet not split block, 
					 so use this specify to fill content-length
  * @return 0: successfully
			-1, faild, cant get content pointer or cant ensure content length
  * @remark 

  ********************************************************************************************/	
int Http_FillContentLength(void *buffer, size_t size, int specify)
{
	char string[32] = "";
	int contentLength = 0;
	if(specify == 0)
	{
		char *content = Http_Content(buffer);
		if(content == NULL)
		{	return -1;	}
		contentLength = Http_ContentLength(buffer, size);
		if(contentLength < 0)
		{	return -1;	}
	}
	else
	{	contentLength = specify;	}
	
	sprintf(string, "Content-Length: %d", contentLength);
	
	return Http_AddHeader(buffer, size, string);
}


/*********************************************************************************************

	http little tool

  ********************************************************************************************/	
char *Http_Content(void *buffer)
{
	char *content = strstr((char*)buffer, "\r\n\r\n");
	if(content == NULL)
	{	return NULL;	}
	content += 4;
	
	return content;
}

char *Http_Tail(void *buffer, size_t size)
{
	/* find last content char */
	char *tail = (char *)buffer;
	for(int i=size-1; i>=0; i-- )
	{
		if(tail[i] != 0)
		{	return tail + i;	}
	}
	
	return NULL;
}

int Http_ContentLength(void *buffer, size_t size)
{
	char *content = Http_Content(buffer);
	char *tail = Http_Tail(buffer, size);
	
	if(content == NULL || tail == NULL)
	{	return -1;	}
	
	return ((uint32_t)tail - (uint32_t)content + 1);
}
int Http_PacketLength(void *buffer, size_t size)
{
	char *tail = Http_Tail(buffer, size);
	
	if(tail == NULL)
	{	return -1;	}
	
	return ((uint32_t)tail - (uint32_t)buffer + 1);
}

